Skip to content

Fix 5 SonarQube issues including cognitive complexity and method length#1741

Open
sonarqube-agent[bot] wants to merge 1 commit into
masterfrom
remediate-master-20260623-230115-06843aa9
Open

Fix 5 SonarQube issues including cognitive complexity and method length#1741
sonarqube-agent[bot] wants to merge 1 commit into
masterfrom
remediate-master-20260623-230115-06843aa9

Conversation

@sonarqube-agent

Copy link
Copy Markdown
Contributor

This PR was automatically created by the Remediation Agent's Scheduled backlog remediation feature.

Why these issues? Prioritized the CRITICAL severity cognitive complexity issue (S3776) alongside high-value MAJOR issues with clear, automated remediation: method refactoring (S138, S3776), idiomatic Java patterns (S3824), performance optimization (S8786), and conditional logging (S2629). These fixes deliver substantial code quality and performance improvements with minimal risk.

Resolved a critical cognitive complexity issue by extracting complex logic into helper methods, split an oversized 193-line method into focused smaller methods, optimized a regex pattern vulnerable to super-linear backtracking, improved conditional logging to avoid unnecessary method invocations, and modernized Map usage with computeIfAbsent patterns. These changes enhance code maintainability, performance, and adherence to SonarQube quality standards.

View Project in SonarCloud


Fixed Issues

java:S3824 - Replace this "Map.containsKey()" with a call to "Map.computeIfAbsent()". • MAJORView issue

Location: php:php-checks/src/main/java/org/sonar/php/checks/phpunit/NoAssertionInTestCheck.java:130

Why is this an issue?

It’s a common pattern to test the result of a java.util.Map.get() against null or calling java.util.Map.containsKey() before proceeding with adding or changing the value in the map. However the java.util.Map API offers a significantly better alternative in the form of the computeIfPresent() and computeIfAbsent() methods. Using these instead leads to cleaner and more readable code.

What changed

This hunk fixes the code smell where Map.containsKey() was used followed by Map.put() with the same key, instead of using the more concise and readable Map.computeIfAbsent() or similar API. The original code checked !assertionInMethod.containsKey(methodDeclaration) and then called assertionInMethod.put(methodDeclaration, false) inside the if-block. The fix replaces this pattern with assertionInMethod.putIfAbsent(methodDeclaration, false) == null, which atomically checks for the key's absence and inserts the value in a single call, making the code cleaner and more idiomatic.

--- a/php-checks/src/main/java/org/sonar/php/checks/phpunit/NoAssertionInTestCheck.java
+++ b/php-checks/src/main/java/org/sonar/php/checks/phpunit/NoAssertionInTestCheck.java
@@ -130,2 +130,1 @@ public class NoAssertionInTestCheck extends PhpUnitCheck {
-      if (!assertionInMethod.containsKey(methodDeclaration)) {
-        assertionInMethod.put(methodDeclaration, false);
+      if (assertionInMethod.putIfAbsent(methodDeclaration, false) == null) {
java:S138 - This method has 193 lines, which is greater than the 100 lines authorized. Split it into smaller methods. • MAJORView issue

Location: php:php-checks/src/main/java/org/sonar/php/checks/utils/PhpUnitCheck.java:39

Why is this an issue?

A method that grows too large tends to aggregate too many responsibilities. Such method inevitably become harder to understand and therefore harder to maintain.

What changed

This hunk replaces the beginning of the overly long assertions() method by delegating to four smaller helper methods (arrayContainsAndEqualityAssertions(), fileAndDirectoryAssertions(), typeStateAndIdentityAssertions(), stringXmlJsonAndConstraintAssertions()), each returning a Stream<Assertion>. This splits the original 193-line method into smaller, focused methods, bringing the line count of assertions() well below the 100-line threshold and resolving the code smell about methods that are too large.

--- a/php-checks/src/main/java/org/sonar/php/checks/utils/PhpUnitCheck.java
+++ b/php-checks/src/main/java/org/sonar/php/checks/utils/PhpUnitCheck.java
@@ -39,0 +40,10 @@ public abstract class PhpUnitCheck extends PHPVisitorCheck {
+    return Stream.of(
+      arrayContainsAndEqualityAssertions(),
+      fileAndDirectoryAssertions(),
+      typeStateAndIdentityAssertions(),
+      stringXmlJsonAndConstraintAssertions())
+      .flatMap(s -> s)
+      .collect(Collectors.toMap(e -> e.name().toLowerCase(Locale.ENGLISH), e -> e));
+  }
+
+  private static Stream<Assertion> arrayContainsAndEqualityAssertions() {
java:S2629 - Invoke method(s) only conditionally. • MAJORView issue

Location: php:sonar-php-plugin/src/main/java/org/sonar/plugins/php/reports/phpunit/PhpUnitReportImporter.java:38

Why is this an issue?

Some method calls can effectively be "no-ops", meaning that the invoked method does nothing, based on the application’s configuration (eg: debug logs in production). However, even if the method effectively does nothing, its arguments may still need to evaluated before the method is called.

What changed

This hunk fixes the code smell where methods like reportName() and reportPathKey() are invoked unconditionally as arguments to a logging call. By adding && logger().isInfoEnabled() to the condition, the code ensures that the subsequent logging statement (which calls reportName() and reportPathKey()) is only reached when the logger's info level is actually enabled. This prevents the unnecessary evaluation of those method calls when the log level is too high to display the message, addressing the performance penalty of invoking methods only to pass their results to a no-op logging call.

--- a/sonar-php-plugin/src/main/java/org/sonar/plugins/php/reports/phpunit/PhpUnitReportImporter.java
+++ b/sonar-php-plugin/src/main/java/org/sonar/plugins/php/reports/phpunit/PhpUnitReportImporter.java
@@ -37,1 +37,1 @@ public abstract class PhpUnitReportImporter extends AbstractReportImporter {
-    if (getReportFiles(context).isEmpty()) {
+    if (getReportFiles(context).isEmpty() && logger().isInfoEnabled()) {
java:S3776 - Refactor this method to reduce its Cognitive Complexity from 16 to the 15 allowed. • CRITICALView issue

Location: php:php-checks/src/main/java/org/sonar/php/checks/DeadStoreCheck.java:94

Why is this an issue?

Cognitive Complexity is a measure of how hard it is to understand the control flow of a unit of code. Code with high cognitive complexity is hard to read, understand, test, and modify.

What changed

This hunk replaces the inline logic for processing symbol usages (which included multiple nested if statements, conditions with logical operators, and loop nesting) with a single method call to processSymbolUsage. By extracting this code into a separate method, the cognitive complexity of the verifyBlock method is reduced because the nested conditionals and their associated complexity increments are moved out of the method. This directly addresses the code smell where the verifyBlock method's cognitive complexity exceeded the allowed threshold of 15.

--- a/php-checks/src/main/java/org/sonar/php/checks/DeadStoreCheck.java
+++ b/php-checks/src/main/java/org/sonar/php/checks/DeadStoreCheck.java
@@ -99,14 +99,1 @@ public class DeadStoreCheck extends PHPSubscriptionCheck {
-        Symbol symbol = symbolWithUsage.getKey();
-        if (outOfScope(readSymbols, symbol)) {
-          // These cases are verified by other checks
-          continue;
-        }
-        VariableUsage usage = symbolWithUsage.getValue();
-        if (usage.isWrite() && !usage.isRead()) {
-          if (!willBeRead.contains(symbol) && !shouldSkip(element, symbol)) {
-            context().newIssue(this, element, String.format(MESSAGE_TEMPLATE, symbol.name()));
-          }
-          willBeRead.remove(symbol);
-        } else if (usage.isRead()) {
-          willBeRead.add(symbol);
-        }
+        processSymbolUsage(symbolWithUsage, readSymbols, willBeRead, element);
java:S8786 - Simplify this regular expression to reduce its runtime, as it has super-linear performance due to backtracking. • MAJORView issue

Location: php:php-checks/src/main/java/org/sonar/php/checks/phpunit/NoAssertionInTestCheck.java:46

Why is this an issue?

Regular expression engines use backtracking to try all possible execution paths when evaluating a pattern against an input. In some cases, this leads to non-linear backtracking where the worst-case evaluation time grows polynomially (e.g., O(n²) or O(n³)) with the input size. While not as severe as catastrophic backtracking, such patterns can significantly degrade application performance when processing large or untrusted inputs.

What changed

This hunk fixes the regular expression that exhibited super-linear (polynomial) backtracking performance. The original pattern (assert|verify|fail|pass|should|will|check|expect|validate|.*test).* contained .*test inside a group followed by .*, which caused the regex engine to backtrack excessively on non-matching inputs. The fix restructures the pattern to (assert|verify|fail|pass|should|will|check|expect|validate).*|.*test.*, moving the .*test.* alternative outside the group. This eliminates the ambiguous overlap between .*test and the trailing .* quantifier, reducing the backtracking complexity from super-linear to linear.

--- a/php-checks/src/main/java/org/sonar/php/checks/phpunit/NoAssertionInTestCheck.java
+++ b/php-checks/src/main/java/org/sonar/php/checks/phpunit/NoAssertionInTestCheck.java
@@ -46,1 +46,1 @@ public class NoAssertionInTestCheck extends PhpUnitCheck {
-  private static final Pattern ASSERTION_METHODS_PATTERN = Pattern.compile("(assert|verify|fail|pass|should|will|check|expect|validate|.*test).*");
+  private static final Pattern ASSERTION_METHODS_PATTERN = Pattern.compile("(assert|verify|fail|pass|should|will|check|expect|validate).*|.*test.*");

Have a suggestion or found an issue? Share your feedback here.


SonarQube Remediation Agent uses AI. Check for mistakes.

Fixed issues:
- AZkoVAVQIsbR56mqmhNH for java:S2629 rule
- AZkz3mbD-GVAOO9Z9Iiy for java:S3824 rule
- AZ7dogobU_MVOKqD8-MV for java:S8786 rule
- AZkoU-8TIsbR56mqmhGP for java:S3776 rule
- AZkz3mdx-GVAOO9Z9Ii0 for java:S138 rule

Generated by SonarQube Agent (task: efb36fad-c3d8-4b80-ac8b-5a3d37f5a8b6)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant